import { Asset, isValid } from "cc";
import UIView from "./ui/UIView";


/**资源相关 */
export namespace Resource {

    /**资源加载器错误 */
    export enum LoaderError {
        /**加载中 */
        LOADING,
        /** 未找到或设置加载资源*/
        NO_FOUND_LOAD_RESOURCE,
        /**完美加载 */
        SUCCESS,
    }
    /**资源缓存类型 */
    export enum CacheStatus {
        /**无状态 */
        NONE,
        /**等待释放 */
        WAITTING_FOR_RELEASE,
    }
    /**资源类型 */
    export enum Type {
        /**本地 */
        Local,
        /**远程资源 */
        Remote,
    }

    export interface Data {
        /**resources 目录url 与 type 必须成对出现*/
        url?: string,
        /**资源类型 与 url 必须成对出现 目前支持预加载的资源有cc.Prefab | cc.SpriteFrame | sp.SkeletonData*/
        type?: typeof Asset,
        /**
         * 预加载界面，不需要对url type赋值 
         * 如GameView游戏界面，需要提前直接加载好界面，而不是只加载预置体，
         * 在网络消息来的时间，用预置体加载界面还是需要一定的时间，
         * 从而会造成消息处理不是顺序执行 
         * */
        preloadView?: UIClass<UIView>,
        /**bundle */
        bundle?: BUNDLE_TYPE,
        /**如果是加载的目录，请用dir字段 */
        dir?: string,
    }
    /**资源信息 */
    export class Info {
        /**资源地址 */
        url: string = "";
        /**类型 */
        type: typeof Asset = null!;
        /**资源数据 */
        data: Asset | Asset[] = null!;
        /**是否常驻内存，远程加载资源有效 */
        retain: boolean = false;
        /**包名 */
        bundle: BUNDLE_TYPE = null!;
        /**默认为本地资源 */
        resourceType: Type = Type.Local;

        constructor(info: {
            url?: typeof Info.prototype.url,
            type?: typeof Info.prototype.type,
            data?: typeof Info.prototype.data,
            retain?: typeof Info.prototype.retain,
            bundle?: typeof Info.prototype.bundle,
            resourceType?: typeof Info.prototype.resourceType,
        } = {}) {
            this.url ??= info.url;
            this.type ??= info.type;
            this.data ??= info.data;
            this.retain ??= info.retain;
            this.bundle ??= info.bundle;
            this.resourceType ??= info.resourceType;
        }
    }
    export class CacheData {
        /**是否已经加载完成 */
        isLoaded: boolean = false;
        /**加载完成数据 
         * cc.Prefab 
         * cc.SpriteAtlas 
         * cc.SpriteFrame 
         * cc.AudioClip 
         * cc.Font 
         * sp.SkeletonData 
         * cc.ParticleAsset 
         * cc.Texture2D
         * cc.JsonAsset
         * */
        data: Asset | Asset[] | null = null;
        /**资源信息 */
        info: Info = new Info();
        /**资源缓存类型  */
        status: CacheStatus = CacheStatus.NONE;
        /**在加载过程中有地方获取,加载完成后再回调 */
        getCb: ((data: any) => void)[] = [];
        /**完成回调，在资源正在加载过程中，又有其它地方调用加载同一个资源，此时需要等待资源加载完成，统一回调 */
        finishCb: ((data: any) => void)[] = [];

        constructor(info: {
            path?: string,
            type?: typeof Asset,
            bundle?: BUNDLE_TYPE,
            resourceType?: Type,
            data?: Asset | Asset[] | null
        }) {
            this.info.url ??= info.path; // =>  this.info.url ?? (this.info.url = path); -> 只有为空时才发生赋值，不会覆盖掉原有的值
            this.info.type ??= info.type;
            this.info.bundle ??= info.bundle;
            this.info.resourceType ??= info.resourceType;
            this.data ??= info.data;
        }

        doGet(data: any) {
            for (let i = 0; i < this.getCb.length; i++) {
                if (this.getCb[i]) this.getCb[i](data);
            }
            this.getCb = [];
        }

        doFinish(data: any) {
            for (let i = 0; i < this.finishCb.length; i++) {
                if (this.finishCb[i]) this.finishCb[i](data);
            }
            this.finishCb = [];
        }

        get isInvalid() {
            return this.isLoaded && this.data && !isValid(this.data);
        }
    }

}